package com.zh.flowable.domain.flow.service;

import com.zh.flowable.domain.AuditAction;
import com.zh.flowable.domain.AuditStatus;
import com.zh.flowable.domain.dto.TaskCompleteReqForm;
import com.zh.flowable.support.AutoFlowNoGenerator;
import io.micrometer.common.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@AllArgsConstructor
@Service
public class FlowableService {

    private RuntimeService runtimeService;

    private TaskService taskService;

    private RepositoryService repositoryService;

    private HistoryService historyService;

    private IdentityService identityService;

    /**
     * 部署流程定义
     */
    public String deployProcess(String bpmnFile, String name, String key) {
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource(Path.of("/processes/", bpmnFile).toString())
                .enableDuplicateFiltering()
                .name(name)
                .key(key)
                .deploy();
        return deployment.getId();
    }

    /**
     * 获取部署列表
     */
    public List<Deployment> getDeployments() {
        return repositoryService.createDeploymentQuery().list();
    }

    /**
     * 删除部署
     */
    public void deleteDeployment(String deploymentId) {
        repositoryService.deleteDeployment(deploymentId);
    }

    /**
     * 启动流程实例
     */
    public ProcessInstance startProcess(String processDefinitionKey, String applicant, Map<String, Object> variables) {
        var flowNo = AutoFlowNoGenerator.autoFlowNo(processDefinitionKey);
        var copyVariables = new HashMap<>(variables);
        copyVariables.put("flowNo", flowNo);

        //启动流程实例，并自定义流程实例的业务Key
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, flowNo, copyVariables);
        // 设置初始业务状态
        runtimeService.updateBusinessStatus(instance.getProcessInstanceId(), String.valueOf(AuditStatus.IN_REVIEW.getCode()));

        return instance;
    }

    /**
     * 获取用户任务列表
     */
    public List<Task> getTasks(String assignee, boolean isGroup) {
        if (isGroup) {
            return taskService.createTaskQuery().taskCandidateGroup(assignee).list();
        } else {
            return taskService.createTaskQuery().taskAssignee(assignee).list();
        }
    }

    /**
     * 认领任务
     */
    public void claimTask(String taskId, String approver, String insteadApprover) {
        List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(taskId);
        identityLinks.forEach(identityLink -> {
            log.info("identityLink: {}", identityLink);
        });

        List<String> candidateUsers = new ArrayList<>();
        List<String> candidateGroups = new ArrayList<>();
        for (IdentityLink link : identityLinks) {
            if (IdentityLinkType.CANDIDATE.equals(link.getType()) && link.getGroupId() != null) {
                candidateGroups.add(link.getGroupId());
            }
            if (IdentityLinkType.CANDIDATE.equals(link.getType()) && link.getUserId() != null) {
                candidateUsers.add(link.getUserId());
            }
        }

        if (!candidateGroups.isEmpty()) {
            // 验证用户是否属于任务的任意候选组
            boolean notMember = identityService.createUserQuery()
                    .memberOfGroups(candidateGroups).userId(approver).count() == 0;
            if (notMember) {
                throw new RuntimeException("用户" + approver + " 不属于任务候选组" + candidateGroups);
            }
        } else if (!candidateUsers.isEmpty()) {
            // 验证用户是否属于任务的任意候选用户
            boolean isMember = candidateUsers.contains(approver);
            if (!isMember) {
                throw new RuntimeException("用户" + approver + " 不属于任务候选用户" + candidateUsers);
            }
        } else {
            log.warn("任务{} 没有候选用户或候选组. 忽略认领任务操作", taskId);
            return;
        }

        // 认领任务
        if (StringUtils.isNotBlank(insteadApprover)) {
            taskService.claim(taskId, insteadApprover); //指定代替审批人认领任务
        } else {
            taskService.claim(taskId, approver); //自己认领任务
        }
        log.info("claim task success. taskId: {}, approver: {}", taskId, approver);
    }

    /**
     * 取消认领任务
     */
    public void unclaimTask(String taskId, String approver) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }
        String claimedBy = task.getClaimedBy();
        if (!Objects.equals(claimedBy, approver)) {
            throw new RuntimeException("用户" + approver + " 未认领任务" + taskId + ",取消认领无效");
        }
        //认领任务
        taskService.unclaim(taskId);
        log.info("unclaim task success. taskId: {}", taskId);
    }

    /**
     * 完成任务：推动流程往下走
     */
//    @Transactional
    public void completeTask(String taskId, AuditAction auditAction, String approver, TaskCompleteReqForm form) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }
        // 验证当前审批人是否为任务负责人
        if (!task.getAssignee().equals(approver)) {
            throw new RuntimeException("无权限完成此任务");
        }

        Map<String, Object> variables = new HashMap<>();
        variables.put("taskId", taskId);
        variables.put("approver", approver);
        variables.put("auditAction", auditAction.name()); // 审批回复动作
        variables.put("auditComment", form.getComment() != null ? form.getComment() : ""); // 审批回复文本
        taskService.complete(taskId, approver, variables);
        log.info("complete task success. taskId: {}, approver: {}", taskId, approver);
    }

    /**
     * 查询流程定义
     */
    public List<ProcessDefinition> getProcessDefinitions() {
        return repositoryService.createProcessDefinitionQuery().list();
    }

    /**
     * 根据流程实例ID 查询流程实例详情（包含关联任务）
     */
    public ProcessInstDetail getProcessInstanceDetailById(String processInstId) {
        // 查询流程实例基本信息
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstId)
                .singleResult();
        if (instance == null) {
            throw new RuntimeException("流程实例不存在");
        }

        // 查询该流程实例的所有任务（含历史任务）
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstId)
                .list();

        var variables = runtimeService.getVariables(processInstId);
        var processVariables = instance.getProcessVariables();
        log.info("Instance variables: {}", processVariables);
        log.info("Runtime variables: {}", variables);

        // 构建返回结果
        var result = new ProcessInstDetail();
        result.setInstance(instance);
        result.setTasks(tasks);
        return result;
    }

    /**
     * 根据流程实例业务键 查询流程实例详情（包含关联任务）
     *
     * @param flowNo 业务流程审批单号
     * @return ProcessInstDetail
     */
    public ProcessInstDetail getProcessInstanceDetailByFlowNo(String flowNo) {
        // 查询流程实例基本信息
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceBusinessKey(flowNo)
                .singleResult();
        if (instance == null) {
            log.warn("根据业务键查询流程实例不存在，flowNo: {}", flowNo);
            throw new RuntimeException("流程实例不存在");
        }

        // 查询该流程实例的所有任务（含历史任务）
        var tasks = taskService.createTaskQuery()
                .processInstanceId(instance.getId())
                .list();

        // 构建返回结果
        var result = new ProcessInstDetail();
        result.setInstance(instance);
        result.setTasks(tasks);
        return result;
    }

    public void deleteProcessInstance(String flowNo) {
        // 查询流程实例基本信息
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceBusinessKey(flowNo)
                .singleResult();
        if (instance != null) {

            runtimeService.deleteProcessInstance(instance.getId(), "");
            log.info("删除流程实例成功，flowNo: {}", flowNo);
        } else {
            log.warn("忽略删除操作，流程实例不存在，flowNo: {}", flowNo);
        }
    }

    public HisProcessInstDetail getHistoryProcessInstDetailByFlowNo(String flowNo) {
        var hiInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceBusinessKey(flowNo).singleResult();
        if (hiInstance == null) {
            log.warn("根据业务键查询历史流程实例不存在，flowNo: {}", flowNo);
            throw new RuntimeException("历史流程实例不存在");
        }

        // 查询该流程实例的所有任务（含历史任务）
        var tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(hiInstance.getId())
                .list();

        // 构建返回结果
        var result = new HisProcessInstDetail();
        result.setInstance(hiInstance);
        result.setTasks(tasks);
        return result;
    }
}